package com.codeyang.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codeyang.domain.Prod;
import com.codeyang.domain.ProdComm;
import com.codeyang.domain.ProdTagReference;
import com.codeyang.domain.Sku;
import com.codeyang.mapper.ProdCommMapper;
import com.codeyang.mapper.ProdMapper;
import com.codeyang.mapper.SkuMapper;
import com.codeyang.service.ProdService;
import com.codeyang.service.ProdTagReferenceService;
import com.codeyang.service.SkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述: TO-删除标志-DO
 *
 * @author CodeYang_Site
 * @version 2021/5/24 22:34
 */
@Slf4j
@Service
public class ProdServiceImpl extends ServiceImpl<ProdMapper, Prod> implements ProdService {

    @Autowired
    private ProdMapper prodMapper;

    @Autowired
    private SkuService skuService;

    @Autowired
    private ProdTagReferenceService prodTagReferenceService;

    @Autowired
    private ProdCommMapper prodCommMapper;

    @Autowired
    private SkuMapper skuMapper;

    /**
     * 新增商品涉及到3.4张表
     * 1.prod one to many
     * 2.sku one to many
     * 3tag_reference one to may
     *
     * @param prod
     * @return
     */
    @Override
    public boolean save(Prod prod) {
        log.info("新增商品:{}", JSON.toJSONString(prod));
        //设置的default 属性
        prod.setCreateTime(new Date());
        prod.setUpdateTime(new Date());
        prod.setSoldNum(0); //销量
        prod.setVersion(0); //乐观锁
        prod.setShopId(1L); //商店id
        //处理一下物流
        Prod.DeliveryModeVo deliveryModeVo = prod.getDeliveryModeVo();
        String deliveryMode = JSON.toJSONString(deliveryModeVo);
        prod.setDeliveryMode(deliveryMode);

        if (prod.getStatus().equals(1)) {
            //上架的话添加 上架时间
            prod.setPutawayTime(new Date());
        }
        //插入商品表
        int insert = prodMapper.insert(prod);
        if (insert > 0) {
            //处理另外两张跟商品表关联表的数据
            //处理sku 最小商品单位
            handlerSku(prod);
            //处理标签关系表
            handlerTagReference(prod);
        }

        return insert > 0;
    }


    /**
     * 根据商品id查询 商品信息和sku信息
     *
     * @param prodId
     * @return
     */
    @Override
    public Prod getProdInfoAndSkuById(Long prodId) {
        //1.查询商品信息
        Prod prod = prodMapper.selectById(prodId);
        if (ObjectUtils.isEmpty(prod)) {
            return null;
        }
        //查询sku组装
        List<Sku> list = skuService.list(new LambdaQueryWrapper<Sku>()
                .eq(Sku::getProdId, prodId)
                .eq(Sku::getStatus, 1)
                .orderByDesc(Sku::getUpdateTime)
        );
        prod.setSkuList(list);
        return prod;
    }

    /**
     * 处理 prod 与 sku的关系数据
     * one to many
     *
     * @param prod
     */
    private void handlerSku(Prod prod) {
        //1.拿到前端的 List<sku>数据集合
        List<Sku> skuList = prod.getSkuList();
        //2.判空
        if (CollectionUtils.isEmpty(skuList)) {
            return;
        }
        //不为空就把sku里的一些默认数据完善
        //这里的 数据也是一个引用数据,这里改了 前面插入到DB也会发生改变
        skuList.forEach(sku -> {

            sku.setProdId(prod.getProdId());
            sku.setVersion(0);
            sku.setRecTime(new Date());
            sku.setUpdateTime(new Date());
            sku.setIsDelete(0);
            sku.setActualStocks(sku.getStocks());
        });
        //同时插入 sku表
        skuService.saveBatch(skuList);

    }

    /**
     * 处理 prod 与 tagReference的关系数据
     * one to many
     *
     * @param prod
     */
    private void handlerTagReference(Prod prod) {
        //1.拿到前端的 tagids
        List<Long> tagList = prod.getTagList();
        if (CollectionUtils.isEmpty(tagList)) {
            return;
        }
        // 这里要处理一个中间表 prod one --> 'ProdTagReference' <---one tag 表
        //我们要处理关系:List
        ArrayList<ProdTagReference> referenceArrayList = new ArrayList<>(tagList.size() * 2);
        //这里主要是修改另外一张表 从 tagList中拿数据出来
        tagList.forEach(tagId -> {
            //处理具体关系
            ProdTagReference prodTagReference = new ProdTagReference();
            prodTagReference.setProdId(prod.getProdId());
            prodTagReference.setTagId(tagId);
            prodTagReference.setStatus(Boolean.TRUE);
            prodTagReference.setShopId(1L);
            prodTagReference.setCreateTime(new Date());
            // 这里 添加到 关系集合中
            referenceArrayList.add(prodTagReference);
        });
        //db
        prodTagReferenceService.saveBatch(referenceArrayList);

    }


    /**
     * 查询商品总数量
     * | 查询 指定时间范围内的商品总数量
     * 没有时间参数时查询全部
     *
     * @param start
     * @param end
     * @return
     */
    @Override
    public Integer getTotal(Date start, Date end) {
        Integer integer = prodMapper.selectCount(new LambdaQueryWrapper<Prod>()
                .between(start != null && end != null, Prod::getUpdateTime, start, end));
        return integer;
    }

    /**
     * 根据分页与时间区域得到商品数据
     *
     * @param prodPage 分页对象
     * @param start    开始时间
     * @param end      结束时间
     * @return
     */
    @Override
    public List<Prod> findEsProdPage(Page<Prod> prodPage, Date start, Date end) {
        //1查询商品数据
        // 判断是否有时间区间 没有就是全表扫描
        Page<Prod> selectPage = prodMapper.selectPage(prodPage, new LambdaQueryWrapper<Prod>()
                .between(start != null && end != null, Prod::getUpdateTime, start, end)
        );
        //2.拿到商品集合
        List<Prod> prodList = selectPage.getRecords();
        //3.组装商品里标签属性等
        //3.1 拿到商品ids
        List<Long> ids = prodList.stream().map(Prod::getProdId).collect(Collectors.toList());

        //3.2 精准查询 ids 和 商品标签关系表的数据
        List<ProdTagReference> prodTagReferences = prodTagReferenceService.list(new LambdaQueryWrapper<ProdTagReference>()
                .in(ProdTagReference::getProdId, ids)
        );
        //4循环组装商品关系数据集合
        // 这里是处理 商品标签id和 商品的关系
        prodList.forEach(prod -> {
            //4.1 过滤 判断
            List<Long> tagList = prodTagReferences.stream()
                    .filter(tag -> tag.getProdId().equals(prod.getProdId()))
                    .map(ProdTagReference::getTagId)  //这里只要标签id  超级错误
                    .collect(Collectors.toList());
            //4.2 设置进去
            prod.setTagList(tagList);
        });
        //5 组装商品好评率
        //5.1 in 查询出 商品好评数据
        List<ProdComm> prodCommList = prodCommMapper.selectList(new LambdaQueryWrapper<ProdComm>().in(ProdComm::getProdId, ids));

        prodList.forEach(prod -> {
            Boolean flag = false;
            if (!CollectionUtils.isEmpty(prodCommList)) {
                // 拿到商品对应的评论的集合
                List<ProdComm> currentProdComms = prodCommList.stream()
                        .filter(comm -> comm.getProdId().equals(prod.getProdId()))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(currentProdComms)) {
                    //拿到总评数
                    int total = currentProdComms.size();
                    //拿到好评数
                    int size = currentProdComms.stream().filter(comm -> comm.getEvaluate().equals(0))
                            .collect(Collectors.toList()).size();
                    if (size != 0) {
                        //那就要计算好评率
                        flag = false;
                        // count/total * 100
                        BigDecimal goodLv = new BigDecimal(size)
                                .divide(new BigDecimal(total), 2, BigDecimal.ROUND_HALF_UP)
                                .multiply(new BigDecimal(100));
                        prod.setPraiseNumber((long) size);
                        prod.setPositiveRating(goodLv);

                    }
                }
            }
            if (flag) {
                prod.setPraiseNumber(0L);
                prod.setPositiveRating(new BigDecimal(0));
            }
        });

        return prodList;
    }

    /**
     * 修改库存操作
     *
     * @param data
     */
    @Override
    public void changStock(Map<String, Map<Long, Integer>> data) {
        //TODO 这里data为什么为0了

        Map<Long, Integer> prodMap = data.get("prod");
        //直接循环prod
        prodMap.forEach((proId, count) -> {
            // 这里的可能涉及到多线程并发操作,让mysql的自己的 锁机制去帮我们一条条去执行SQL
            // update prod set stock = stock - changeCount  where prod_id = 1 and stock - changeCount >= 0
            int i = prodMapper.changeStock(proId, count);

            if (i < 0) {
                throw new RuntimeException("商品库存减失败");
            }
        });

        Map<Long, Integer> skuMap = data.get("sku");
        skuMap.forEach((skuId, count) -> {
            int i = skuMapper.changeStock(skuId, count);
            if (i <= 0) {
                // 直接回滚
                throw new RuntimeException("减库存失败");
            }
        });

    }
}
